<?php

namespace App\Http\Middleware;

use App\Master\Enum\RedisKeyEnum;
use App\Models\Arts\UserModel;
use App\Utils\AppResult;
use App\Utils\Control\ActionUtil;
use App\Utils\Control\AuthUser;
use App\Utils\Encrypt\Token;
use App\Utils\LogUtil;
use App\Utils\Encrypt\TokenUtil;
use App\Utils\RedisUtil;
use Closure;
use Illuminate\Support\Facades\Cache;

class ApiAgent
{
    // 日志模块名称
    const LOG_MODULE = 'ApiAgent-Middleware-Log';
    const LOG_ACTION = 'verifyToken';

    /**
     *
     *
     * @param \Illuminate\Http\Request $request
     * @param \Closure $next
     * @return mixed
     * @throws \Exception
     */
    public function handle($request, Closure $next)
    {
        //日志统一写入
        register_shutdown_function([new LogUtil, 'close']);
        LogUtil::getInstance('Api/'); //设置日志存入通道

        $path = $request->path();

        //路由白名单
        if (!in_array($path, self::whiteList())) {
            //当前接口请求控制器
            $controller = ActionUtil::getInstance()->actions();

            //接口限流，写到中间件中
            if (!RedisUtil::getInstance(RedisKeyEnum::API_REQUEST_TRAFFIC)->requestLimit($path, 1, 10)) {
                LogUtil::info('请求次数过多', $controller['controller'], $controller['action'], ['path' => $path]);
                return AppResult::response206('当前访问人数过多，请稍后再试！');
            }

            // 记录用户请求参数
            LogUtil::info('请求参数', $controller['controller'], $controller['action'], $request->all());

            // 验证token 白名单
            if (!in_array($path, self::tokenWhiteList())) {
                //获取token 如何存在则验证并获取账户信息
                $token = $request->header('token');
                if (!empty($token)) {
                    if (!$user_id = $this->checkToken($token)) {
                        return AppResult::response400('登录失效，请重新登录');
                    }

                    //查询并记录用户信息
                    $user = Cache::remember('user_id_' . $user_id, 7200, function () use ($user_id) {
                        return UserModel::getUserInfoByUserId($user_id);
                    });
                    if (!$user) {
                        //防止在缓存后操作得用户登录重试，清除缓存
                        Cache::forget('user_id_' . $user_id);
                        LogUtil::warning('账号不存在', $controller['controller'], $controller['action'], ['user_id' => $user_id]);
                        return AppResult::response400('登录失效，请重新登录');
                    }
                    LogUtil::info('用户编号', $controller['controller'], $controller['action'], $user_id);
                    AuthUser::getInstance()->set(json_decode(json_encode($user), true));
                }
            }
        }

        $response = $next($request);

        return $response;
    }

    /**
     * 校验token
     *
     * @param string $token
     * @return int|mixed|string
     * @throws \Exception
     */
    public function checkToken(string $token){
        $action = ActionUtil::getInstance()->get();

        LogUtil::info('token 验证开始', $action['controller'], $action['action'], $token);
        //设置一个假token 用于测试
        if(strpos($token,'testuid_') !== false){
            $user_id = intval(substr($token,8));
        } else {
            $token_res = Token::check($token);
            //验证参数信息
            if (!$token_res) {
                LogUtil::warning('token 验证失败',  $action['controller'], $action['action'], $token_res);
                return false;
            }

            //签发时间大于当前服务器时间验证失败
            if (!isset($token_res['iat']) || $token_res['iat'] > time()) {
                LogUtil::warning('token 未生效',  $action['controller'], $action['action'], $token_res);
                return false;
            }

            //过期时间小于当前服务器时间验证失败
            if (!isset($token_res['exp']) || $token_res['exp'] < time()) {
                LogUtil::warning('token 已失效',  $action['controller'], $action['action'], $token_res);
                return false;
            }

            //验证参数信息
            if (empty($token_res['data']['user_id'])) {
                LogUtil::warning('token 参数不全',  $action['controller'], $action['action'], $token_res);
                return false;
            }
            $user_id = $token_res['data']['user_id'];
        }
        return $user_id;
    }

    // 路由白名单
    public function whiteList()
    {
        return [];
    }

    //token白名单
    public function tokenWhiteList(): array
    {
        return [
            'api/v1/passport/login',
            'api/v1/passport/register',
            'api/v1/passport/mobileLogin',
            'api/v1/passport/mobileRegister',
            'api/v1/passport/thirdLogin',
            'api/v1/passport/loginWxMiniPhone',
            'api/v1/sms/send',
            'api/v1/sms/check',
        ];
    }
}
